/*
   Envia una peticion de interseccion sobre HTTP/XML para ihttp_server

   El cliente de esta aplicacion es: ihttp_server.p => Transporte: http::Transport.
*/
#include <iostream>

#include <string.h>

#include <nemesis.h>
#include <nemesis.comm.h>

#include <nemesis.app.functions.h>

#include <nemesis.xml.DocumentFile.h>

#include <nemesis.io.TextReader.h>

#include <nemesis.http.Request.h>
#include <nemesis.http.Response.h>
#include <nemesis.http.Handler.h>
#include <nemesis.http.Transport.h>
#include <nemesis.http.functions.h>

class MyHandler : public http::Handler {
public:
   MyHandler () : http::Handler ("ihttp_client::MyHandler") {;}

private:
   http::Response a_httpResponse;

   void evRequest (ClientSocket&, const http::Request&) throw (RuntimeException) {;}
   void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException);
};

class MyCommunicator : public Communicator {
public:
   MyCommunicator () : Communicator (), a_httpRequest (Message::Mode::CopyMemory)
   {
      a_httpRequest.setMethod (http::Method::Type::Post);
      a_httpRequest.setURI ("ihttp_client");
   }

private:
   MyHandler a_httpHandler;
   http::Request a_httpRequest;

   void eventReceiveMessage (ClientSocket &, const Message&) throw (RuntimeException);
   void eventStartup () throw (RuntimeException);
};

class IHTTPClient : public nemesis::comm::Application {
public:
   IHTTPClient ();

   Server* getServer () const throw () { return a_server; }

private:
   MyCommunicator a_communicator;
   Server* a_server;

   void initialize () throw (RuntimeException);
   void run () throw (RuntimeException);
};

using namespace std;

int main (int argc, const char** argv)
{
   CommandLine& commandLine (CommandLine::instanciate ());
   IHTTPClient app;

   http::functions::initialize ();

   try {
      commandLine.initialize (argv, argc);
      commandLine.verify ();

      Logger::setLevel (Logger::Debug);
      Logger::initialize ("ihttp_client", new TraceWriter ("file.trace", 4096000));

      app.start ();
   }
   catch (Exception& ex) {
      cout << ex.asString () << endl;
   }

   return 0;
}

IHTTPClient::IHTTPClient () :
   Application ("ihttp_client", "IHTTPClient", "1.0.0")
{
   CommandLine& commandLine (CommandLine::instanciate ());

   commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas.");
   commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP Puerto en el que el servidor atiende respuestas.");
   commandLine.add ("xml", CommandLine::Argument::Mandatory, "Documento XML que contiene la peticion");
   commandLine.add ("nocheck", CommandLine::Argument::Optional, "Indicador para que no comprueba la validaded del HTML", false);
   commandLine.add ("version", CommandLine::Argument::Optional, "Indica la version HTTP usada para enviar");
}

void IHTTPClient::initialize () 
   throw (RuntimeException)
{
   CommandLine& cl (CommandLine::instanciate ());

   Network& network = Network::instanciate ();

   Host* host = network.find ("host000");
   host->assign (network.find (Device::asAddress (cl.getValue ("a"))));
   a_server = host->createServer ("http_server", cl.getIntegerValue ("p"), true, &http::Transport::getFactory ());
}

void IHTTPClient::run ()
   throw (RuntimeException)
{
   a_communicator.accept ();
}

void MyCommunicator::eventStartup ()
   throw (RuntimeException)
{
   CommandLine& cl (CommandLine::instanciate ());

   const char* filename = cl.getValue ("xml");

   if (cl.exists ("nocheck") == false) {
      xml::DocumentFile xmlDocument;
      xmlDocument.initialize (filename);
   
      const char* xmlToSend = xmlDocument.getContent ();
      a_httpRequest.setBody (DataBlock (xmlToSend, nemesis_strlen (xmlToSend), false));
   }
   else {
      io::TextReader reader;
      reader.open (filename);
      DataBlock body (true);
      const char* line;

      while ((line = reader.fetch ()) != NULL)
         body.append (line, nemesis_strlen (line));

      http::Header* header = a_httpRequest.createHeader (http::Header::Type::Connection);
      header->setValue ("   Keep-Alive    ");

      a_httpRequest.setBody (body);
   }

   if (cl.exists ("version"))
      a_httpRequest.setVersion (cl.getValue ("version"));
   
   static_cast <IHTTPClient&> (nemesis::comm::functions::getApp ()).getServer ()->send (a_httpRequest);
}

void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const Message& message)
   throw (RuntimeException)
{
   LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", FILE_LOCATION));

   if (clientSocket.support (http::Transport::className ()) == false)
      return;

   a_httpHandler.apply (clientSocket, message);
}

void MyHandler::evResponse (ClientSocket& clientSocket, const http::Response& response)
   throw (RuntimeException)
{
   const DataBlock& body = response.getBody ();
   
   DataBlock swap (true);
   
   swap = body;
   swap += char (0);

   cout << "HTTP StatusCode: " << response.getStatusCode () << endl;
   cout << "HTTP Text: " << response.getReasonPhrase () << endl;
   cout << "Resultado: \n" << swap.getData () << endl << endl;
   
   app::functions::component <Communicator> (FILE_LOCATION)->requestStop ();
}

